package com.bridge.processor;


import com.bridge.domain.BeanDefinition;
import com.bridge.enums.BridgeErrorEnum;
import com.bridge.exception.BridgeProcessFailException;
import com.bridge.log.LogHandler;
import com.bridge.utils.PropUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.util.ReflectionUtils;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Modifier;

import static com.bridge.domain.Constants.LOAD_FORMAT;
import static com.bridge.domain.Constants.PRINT_LOG_FORMAT;

/**
 * @author Jay
 * @version v1.0
 * @description 重载属性值
 * @date 2018-12-27 15:51
 */
@Slf4j
public class RefreshBeanField {

    private RefreshBeanField() {
        throw new BridgeProcessFailException(BridgeErrorEnum.NOT_INSTANTIATION_ERROR);
    }

    private static BeanFactory thisBeanFactory;


    public static void setBeanFactory(BeanFactory beanFactory) {
        thisBeanFactory = beanFactory;
    }

    /**
     * 刷新bean
     *
     * @param beanDefinition
     * @param value
     */
    public static void refresh(BeanDefinition beanDefinition, final String value) {
        Object bean = thisBeanFactory.getBean(beanDefinition.getBeanName());
        if (bean == null) {
            return;
        }
        // 获取propertyDescriptor对象，继而可以操作属性值
        BeanWrapper beanWrapper = new BeanWrapperImpl(bean);
        PropertyDescriptor propertyDescriptor = null;
        PropertyDescriptor[] propertyDescriptors = beanWrapper.getPropertyDescriptors();
        if (propertyDescriptors != null && propertyDescriptors.length > 0) {
            for (PropertyDescriptor item : propertyDescriptors) {
                if (item != null && beanDefinition.getPropertyName().equals(item.getName())) {
                    propertyDescriptor = item;
                }
            }
        }
        // 设置值
        if (propertyDescriptor != null && propertyDescriptor.getWriteMethod() != null) {
            beanWrapper.setPropertyValue(beanDefinition.getPropertyName(), value);
            log.info(PRINT_LOG_FORMAT, beanDefinition.getBeanName(), beanDefinition.getPropertyName(), beanDefinition.getKey(), value);
            // 发送日志至控制台
            LogHandler.info(String.format(LOAD_FORMAT, beanDefinition.getBeanName(), beanDefinition.getPropertyName(), beanDefinition.getKey(), value));
        } else {
            refreshForAnnotationTag(beanDefinition, value, bean);
        }
    }


    /**
     * 刷新annotation的bean的属性
     *
     * @param beanDefinition
     * @param bean
     * @param value
     */
    public static void refreshForAnnotationTag(BeanDefinition beanDefinition, String value, Object bean) {
        ReflectionUtils.doWithFields(bean.getClass(), field -> {
            if (beanDefinition.getPropertyName().equals(field.getName())) {
                try {
                    // 静态属性无法注入
                    if (Modifier.isStatic(field.getModifiers())) {
                        log.error("BridgeValue annotation is not supported static inject : " + field);
                        throw new BridgeProcessFailException(BridgeErrorEnum.UNKNOWN_ERROR.getCode()
                                , "BridgeValue annotation is not supported static inject");
                    }
                    Object valueAfterConvert = PropUtils.convertValue(field.getType(), value);
                    field.setAccessible(Boolean.TRUE);
                    field.set(bean, valueAfterConvert);
                    log.info(PRINT_LOG_FORMAT, beanDefinition.getBeanName(), beanDefinition.getPropertyName(), beanDefinition.getKey(), value);
                    // 发送日志至控制台
                    LogHandler.info(String.format(LOAD_FORMAT, beanDefinition.getBeanName(), beanDefinition.getPropertyName(), beanDefinition.getKey(), value));
                } catch (Exception e) {
                    throw new BridgeProcessFailException(BridgeErrorEnum.UNKNOWN_ERROR.getCode(), e.getMessage());
                }
            }
        });
    }

}
